package oauth2

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/github"
	"golang.org/x/oauth2/google"
)

// Provider 类型
type Provider string

const (
	ProviderGitHub Provider = "github"
	ProviderGoogle Provider = "google"
)

// UserInfo 用户信息
type UserInfo struct {
	ID       string `json:"id"`
	Username string `json:"username"`
	Email    string `json:"email"`
	Name     string `json:"name"`
	Avatar   string `json:"avatar"`
}

// OAuth2Manager OAuth2 管理器
type OAuth2Manager struct {
	providers map[string]*oauth2.Config
	stateMap  map[string]string
}

// NewOAuth2Manager 创建 OAuth2 管理器
func NewOAuth2Manager() *OAuth2Manager {
	return &OAuth2Manager{
		providers: make(map[string]*oauth2.Config),
		stateMap:  make(map[string]string),
	}
}

// RegisterProvider 注册 OAuth2 提供商
func (m *OAuth2Manager) RegisterProvider(name, clientID, clientSecret, redirectURL string) error {
	var config *oauth2.Config

	switch Provider(name) {
	case ProviderGitHub:
		config = &oauth2.Config{
			ClientID:     clientID,
			ClientSecret: clientSecret,
			RedirectURL:  redirectURL,
			Scopes:       []string{"user:email"},
			Endpoint:     github.Endpoint,
		}
	case ProviderGoogle:
		config = &oauth2.Config{
			ClientID:     clientID,
			ClientSecret: clientSecret,
			RedirectURL:  redirectURL,
			Scopes:       []string{"openid", "profile", "email"},
			Endpoint:     google.Endpoint,
		}
	default:
		return fmt.Errorf("不支持的 OAuth2 提供商: %s", name)
	}

	m.providers[name] = config
	return nil
}

// GetAuthURL 获取授权 URL
func (m *OAuth2Manager) GetAuthURL(provider string) (string, error) {
	config, ok := m.providers[provider]
	if !ok {
		return "", fmt.Errorf("未找到提供商: %s", provider)
	}

	state := generateState()
	m.stateMap[state] = provider

	return config.AuthCodeURL(state, oauth2.AccessTypeOffline), nil
}

// ExchangeCode 交换授权码
func (m *OAuth2Manager) ExchangeCode(provider, code, state string) (*oauth2.Token, error) {
	// 验证 state
	expectedProvider, ok := m.stateMap[state]
	if !ok || expectedProvider != provider {
		return nil, fmt.Errorf("无效的 state")
	}
	delete(m.stateMap, state)

	config, ok := m.providers[provider]
	if !ok {
		return nil, fmt.Errorf("未找到提供商: %s", provider)
	}

	return config.Exchange(context.Background(), code)
}

// GetUserInfo 获取用户信息
func (m *OAuth2Manager) GetUserInfo(provider string, token *oauth2.Token) (*UserInfo, error) {
	switch Provider(provider) {
	case ProviderGitHub:
		return m.getGitHubUserInfo(token)
	case ProviderGoogle:
		return m.getGoogleUserInfo(token)
	default:
		return nil, fmt.Errorf("不支持的提供商: %s", provider)
	}
}

// getGitHubUserInfo 获取 GitHub 用户信息
func (m *OAuth2Manager) getGitHubUserInfo(token *oauth2.Token) (*UserInfo, error) {
	client := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(token))

	resp, err := client.Get("https://api.github.com/user")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var user struct {
		ID        int    `json:"id"`
		Login     string `json:"login"`
		Email     string `json:"email"`
		Name      string `json:"name"`
		AvatarURL string `json:"avatar_url"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
		return nil, err
	}

	return &UserInfo{
		ID:       fmt.Sprintf("%d", user.ID),
		Username: user.Login,
		Email:    user.Email,
		Name:     user.Name,
		Avatar:   user.AvatarURL,
	}, nil
}

// getGoogleUserInfo 获取 Google 用户信息
func (m *OAuth2Manager) getGoogleUserInfo(token *oauth2.Token) (*UserInfo, error) {
	client := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(token))

	resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var user struct {
		ID      string `json:"id"`
		Email   string `json:"email"`
		Name    string `json:"name"`
		Picture string `json:"picture"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
		return nil, err
	}

	return &UserInfo{
		ID:       user.ID,
		Username: user.Email,
		Email:    user.Email,
		Name:     user.Name,
		Avatar:   user.Picture,
	}, nil
}

// generateState 生成 state 参数
func generateState() string {
	return fmt.Sprintf("%d", time.Now().UnixNano())
}

